/*
* $Id: DateDraw.cpp 86 2010-05-12 17:32:35Z volok-aleksej@yandex.ru $
*
* Copyright 2009 by Volokitin Alexey
* All rights reserved
*
*/
#include "Common/include.h"
#include "DateDraw.h"
#include "KeyProcess.h"
#include "../EditorItem.h"

#define SIZE_HEADER	25
#define SIZE_WEEK	16
#define SIZE_DAY_CY	20
#define SIZE_DAY_CX	25
#define SIZE_ARROW	20

#define UP_CORNER_TRIANGLE(pos, size) CPoint(pos.x + SIZE_ARROW/2, pos.y + size.cy/2 - 5)
#define DOWN_CORNER_TRIANGLE(pos, size) CPoint(pos.x + SIZE_ARROW/2, pos.y + size.cy/2 + 5)
#define LEFT_CORNER_TRIANGLE(pos, size) CPoint(pos.x + (SIZE_ARROW - 10)/2, pos.y + size.cy/2)
#define RIGHT_CORNER_TRIANGLE(pos, size) CPoint(pos.x - (SIZE_ARROW - 10)/2 + size.cx, pos.y + size.cy/2)

const int aMonthDay[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

CDateDraw::CDateDraw(const std::tstring& strName, CEditorItem* pParent)
: CDrawControl(strName), m_pParent(pParent){
	time_t t;
	if(m_strValue.empty())
		time(&t);
	else
		t = CConvertFunction::ConvertFromDate(m_strValue);
	tm _t;
	localtime_s(&_t, &t);
	m_nYear = _t.tm_year + 1900;
	m_nMonth = _t.tm_mon;
	m_nDay = _t.tm_mday - 1;
	Init();
	m_aKeyProcess.push_back(new CArrawLeft(this));
	m_aKeyProcess.push_back(new CArrawRight(this));
	m_aKeyProcess.push_back(new CArrawUp(this));
	m_aKeyProcess.push_back(new CArrawDown(this));
}
CDateDraw::~CDateDraw(){}

void CDateDraw::SetPos(CPoint pos){
	CPoint posRes = pos - m_rect.TopLeft();
	m_rect.MoveToXY(pos);
}

std::tstring CDateDraw::GetValue(){
	std::tstring strDay = CConvertFunction::ConvertFromInt(m_nDay + 1), strMonth = CConvertFunction::ConvertFromInt(m_nMonth + 1);
	if(m_nDay < 9)
		strDay.insert(strDay.begin(), '0');
	if(m_nMonth < 9)
		strMonth.insert(strMonth.begin(), '0');
	return strDay + _T(".") + strMonth + _T(".") + CConvertFunction::ConvertFromInt(m_nYear);
}

void CDateDraw::Resize(){
	int daywith1 = (int)m_aDays.size() - 7 + m_nWDay;
	int nline;
	if(!div(daywith1, 7).rem)
		nline = daywith1/7 + 1;
	else
		nline = daywith1/7 + 2;
	m_rect.bottom = m_rect.top + SIZE_HEADER + SIZE_WEEK + nline*SIZE_DAY_CY;
}

void CDateDraw::PaintActive(CDC* dc){
	CBrush brush;
	brush.CreateSolidBrush(GetSysColor(COLOR_WINDOW));
	dc->FillRect(m_rect, &brush);
	brush.DeleteObject();
	PaintNonActive(dc);
}

void CDateDraw::PaintNonActive(CDC* dc){
	CRect rect(m_rect.left + m_rect.Size().cx/2 - SIZE_DAY_CX*7/2, m_rect.top,
		m_rect.left + m_rect.Size().cx/2 + SIZE_DAY_CX*7/2, m_rect.bottom);
//Paint Header
	CFont *font = CCommonFunction::GetFont(_T("MS Sans Serif"), 16, true, false);
	HGDIOBJ oldFont = dc->SelectObject(font->m_hObject);
	CBrush brush;
	brush.CreateSolidBrush(CCommonFunction::GetBeeColor());
	CRect rectHeader(rect.left, rect.top, rect.right + 1, rect.top + SIZE_HEADER);
	dc->FillRect(rectHeader, &brush);
	brush.DeleteObject();
	dc->SetBkMode(TRANSPARENT);
	dc->DrawText(IApplication::GetApp()->GetLanguageManager()->GetString(JANUARY_ID + m_nMonth).c_str(),
		CRect(rectHeader.left, rectHeader.top, rectHeader.left + rectHeader.Size().cx/2 + SIZE_ARROW, rectHeader.bottom), DT_CENTER|DT_SINGLELINE|DT_VCENTER);
	dc->DrawText(CConvertFunction::ConvertFromInt(m_nYear).c_str(),
		CRect(rectHeader.left + rectHeader.Size().cx/2 + SIZE_DAY_CY, rectHeader.top, rectHeader.right, rectHeader.bottom), DT_CENTER|DT_SINGLELINE|DT_VCENTER);
	dc->SelectObject(oldFont);
	font->DeleteObject();
	delete font;
	CPoint topleft = rectHeader.TopLeft();
	CSize sizearrow(SIZE_ARROW, rectHeader.Size().cy);
	if(m_nMonth != 0)
		PaintArrow(dc, topleft, sizearrow, true);
	topleft.SetPoint(rectHeader.left + rectHeader.Size().cx/2, rectHeader.top);
	if(m_nMonth != 11)
		PaintArrow(dc, topleft, sizearrow, false);
	topleft.SetPoint(rectHeader.left + rectHeader.Size().cx/2 + SIZE_ARROW, rectHeader.top);
	PaintArrow(dc, topleft, sizearrow, true);
	topleft.SetPoint(rectHeader.right - SIZE_ARROW, rectHeader.top);
	PaintArrow(dc, topleft, sizearrow, false);
//Paint Week days
	font = CCommonFunction::GetFont(_T("MS Sans Serif"), 14, false, false);
	dc->SetBkMode(TRANSPARENT);
	oldFont = dc->SelectObject(font->m_hObject);
	CRect rectWeek(rect.left, rect.top + SIZE_HEADER, rect.left + SIZE_DAY_CX, rect.top + SIZE_HEADER + SIZE_WEEK);
	brush;
	brush.CreateSolidBrush(GetSysColor(COLOR_WINDOW));
	for(int i = 0, day = DAY_MONDAY_ID ; i < 7; i++, rectWeek.MoveToX(rectWeek.right), day++){
		dc->FillRect(rectWeek, &brush);
		dc->DrawText(IApplication::GetApp()->GetLanguageManager()->GetString(day).c_str(), rectWeek, DT_CENTER|DT_SINGLELINE|DT_VCENTER);
	}
	brush.DeleteObject();
	dc->SelectObject(oldFont);
	font->DeleteObject();
	delete font;
//Paint days
	int nWDay = m_nWDay, nline = 0;
	dc->Rectangle(rect.left, rectWeek.bottom, rect.left + SIZE_DAY_CX * nWDay + 1, rectWeek.bottom + SIZE_DAY_CY + 1);
	for(std::vector<CDayDraw>::iterator it = m_aDays.begin(); it != m_aDays.end(); it++, nWDay++){
		if(nWDay == 7){
			nWDay = 0;
			nline++;
		}
		it->SetBeginPoint(CPoint(rect.left + SIZE_DAY_CX * nWDay, rectWeek.bottom + nline * SIZE_DAY_CY));
		it->Paint(dc);
	}
	dc->Rectangle(rect.left + SIZE_DAY_CX * nWDay, rectWeek.bottom + nline*SIZE_DAY_CY, rect.right + 2, rectWeek.bottom + (nline + 1)*SIZE_DAY_CY + 1);
	//Paint borders
	CPen pen;
	pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
	HGDIOBJ oldPen = dc->SelectObject(pen);
	dc->MoveTo(rect.TopLeft());
	dc->LineTo(CPoint(rect.left, rect.bottom + 1));
	dc->LineTo(CPoint(rect.right + 1, rect.bottom + 1));
	dc->LineTo(CPoint(rect.right + 1, rect.top));
	dc->LineTo(rect.TopLeft());
	dc->MoveTo(CPoint(rect.left, rect.top + SIZE_HEADER));
	dc->LineTo(CPoint(rect.right, rect.top + SIZE_HEADER));
	dc->MoveTo(CPoint(rect.left, rect.top + SIZE_HEADER + SIZE_WEEK));
	dc->LineTo(CPoint(rect.right, rect.top + SIZE_HEADER + SIZE_WEEK));
	dc->SelectObject(oldPen);
	pen.DeleteObject();
}

void CDateDraw::PaintArrow(CDC* dc, CPoint topleft, CSize sizearrow, bool bLeft){
	CBrush brush;
	brush.CreateSolidBrush(RGB(0, 0, 0));
	CPoint points[4];
	CRgn region;
	points[0] = UP_CORNER_TRIANGLE(topleft, sizearrow);
	if(bLeft)
		points[1] = LEFT_CORNER_TRIANGLE(topleft, sizearrow);
	else
		points[1] = RIGHT_CORNER_TRIANGLE(topleft, sizearrow);
	points[2] = DOWN_CORNER_TRIANGLE(topleft, sizearrow);
	points[3] = UP_CORNER_TRIANGLE(topleft, sizearrow);
	region.CreatePolygonRgn(points, 4, WINDING);
	dc->FillRgn(&region, &brush);
	region.DeleteObject();
	brush.DeleteObject();
}

void CDateDraw::Init(){
	tm t={0};
	t.tm_mday = 1;
	t.tm_mon = m_nMonth;
	t.tm_year = m_nYear - 1900;
	time_t timer = mktime(&t);
	m_nWDay = t.tm_wday;
	if(!m_nWDay)
		m_nWDay = 6;
	else
		m_nWDay--;
	int nDays = 0;
	if(m_nMonth == 1 && !div(t.tm_year, 4).rem)
		nDays = 29;
	else
		nDays = aMonthDay[m_nMonth];
	m_aDays.clear();
	for(int i = 0; i < nDays; i++){
		m_aDays.push_back(CDayDraw(i+1));
		m_aDays.back().SetSize(CSize(SIZE_DAY_CX, SIZE_DAY_CY));
		if(i == m_nDay)
			m_aDays.back().SetSel(true);
	}
}

void CDateDraw::SetDay(int nDay){
	if((int)m_aDays.size() > m_nDay)
		m_aDays[m_nDay].SetSel(false);
	m_nDay = nDay;
	if((int)m_aDays.size() > m_nDay)
		m_aDays[m_nDay].SetSel(true);
}

void CDateDraw::OffsetDay(int offset){
	if(offset < 0 && -offset > m_nDay){
		if(m_nMonth == 0){
			m_nMonth = 11;
			m_nYear--;
		}else
			m_nMonth--;
		int offsetNew = offset + m_nDay + 1;
		Init();
		m_pParent->ResizeItem();
		SetDay((int)m_aDays.size() - 1);
		OffsetDay(offsetNew);
	}else if(offset > 0 && offset + m_nDay >= (int)m_aDays.size()){
		if(m_nMonth == 11){
			m_nMonth = 0;
			m_nYear++;
		}else
			m_nMonth++;
		int offsetNew = offset + m_nDay - (int)m_aDays.size();
		Init();
		m_pParent->ResizeItem();
		SetDay(0);
		OffsetDay(offsetNew);
	}else
		SetDay(m_nDay + offset);
}

bool CDateDraw::ProcessMouse(unsigned int nChar, CPoint pos, int param){
	if(nChar != WM_LBUTTONDOWN)
		return false;
	CRect rect(m_rect.left + m_rect.Size().cx/2 - SIZE_DAY_CX*7/2, m_rect.top,
		m_rect.left + m_rect.Size().cx/2 + SIZE_DAY_CX*7/2, m_rect.bottom);
	if(pos.y > rect.top + SIZE_HEADER + SIZE_WEEK){
		for (std::vector<CDayDraw>::iterator it = m_aDays.begin(); it != m_aDays.end(); it++){
			if(it->GetRect().PtInRect(pos)){
				SetDay(int(it - m_aDays.begin()));
				break;
			}
		}
	}else if(pos.y < rect.top + SIZE_HEADER && pos.x < rect.left + SIZE_ARROW){
		if(m_nMonth != 0){
			m_nMonth--;
			Init();
		}
	}else if(pos.y < rect.top + SIZE_HEADER && pos.x < rect.left + rect.Size().cx/2 + SIZE_ARROW &&
												pos.x > rect.left + rect.Size().cx/2){
		if(m_nMonth != 11){
			m_nMonth++;
			Init();
		}
	}else if(pos.y < rect.top + SIZE_HEADER && pos.x > rect.left + rect.Size().cx/2 + SIZE_ARROW &&
												pos.x < rect.left + rect.Size().cx/2 + SIZE_ARROW*2){
		m_nYear--;
		Init();
	}else if(pos.y < rect.top + SIZE_HEADER && pos.x > rect.right - SIZE_ARROW){
		m_nYear++;
		Init();
	}
	return true;
}
